#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>
#include<vector>
#include<mutex>
using namespace std;
#include"thread.hpp"
#include"LockGuard.hpp"
using namespace ThreadModule;
 
int g_tickets=10000;//共享资源，未保护
const int num=4;
 
//因为锁变成局部的，为了让route可以访问互斥锁，且统计每个线程抢到了多少张票，定义一个类
class ThreadData
{
public:
    ThreadData(int &tickets,std::string name,pthread_mutex_t &mutex)
        :_tickets(tickets),_name(name),_mutex(mutex),_total(0)
    { }
    ~ThreadData()
    {   }
public:
    int &_tickets;//所有线程最终都会引用同一个全局变量g_tickets
    std::string _name;
    int _total;
    pthread_mutex_t &_mutex;
};
 
void route(ThreadData *td)
{
    //票没抢完就一直抢
    while(true)
    {
        LockGuard guard(&td->_mutex);
        //pthread_mutex_lock(&td->_mutex);//申请锁
        //还有票，可以继续抢
        if(td->_tickets>0)//1
        {
            usleep(1);
            //目前剩下的票数
            printf("%s running, get tickets:%d\n",td->_name.c_str(),td->_tickets);//2
            td->_tickets--;//3
            td->_total++;
            //pthread_mutex_unlock(&td->_mutex);//释放锁
        }
        else//已经没票了，不能抢了，退出
        {
            //pthread_mutex_unlock(&td->_mutex);//释放锁
            break;
        }
 
    }
}
 
int main()
{
    //一把局部的锁
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,nullptr);//初始化互斥锁
 
    std::vector<Thread<ThreadData*>> threads;
    std::vector<ThreadData*> datas;
    //创建线程
    for(int i=0;i<num;i++)
    {
        std::string name="thread-"+std::to_string(i+1);
        ThreadData* td = new ThreadData(g_tickets,name,mutex);
        threads.emplace_back(route,td,name);
        datas.emplace_back(td);
    }
 
    //启动线程
    for(auto &threads:threads)
    {
        threads.Start();
    }
 
    //等待线程
    for(auto &threads:threads)
    {
        threads.Join();
        //std::cout<<"wait thread done, thread is: "<<threads.name()<<std::endl;
    }
 
    for(auto data:datas)
    {
        std::cout<<data->_name<<" : "<<data->_total<<std::endl;
        delete data;
    }
    pthread_mutex_unlock(&mutex);
    //
    return 0;
}